class Card {
  dom: HTMLElement

  constructor(dom: HTMLElement) {
    this.dom = dom;
  }
}

class Game{

  //游戏的dom
  gameDom: HTMLElement;
  /*
    height: 650px;
    width: 500px;
  */
  //游戏Dom的宽度
  gameDomWidth: Number;
  //游戏Dom的高度
  gameDomHeight: Number;
  //游戏为n * n的方格
  n: number;
  //存放卡片的数组
  cards: any[];
  //初始卡片的数组
  originCards: any[];
  //图片地址
  imgUrl: string;

  //当前空白卡片所在的位置,i
  blankCardI: number;
  //当前空白卡片所在的位置,j
  blankCardJ: number;

  //随机卡片的次数
  randomCount: number;

  constructor(n?: number) {
    this.gameDom = document.getElementById('game_content')!;
    this.gameDomWidth = 500;
    this.gameDomHeight = 650;
    this.n = (n == null) ? 3 : n;
    this.imgUrl = '';
    this.cards = [];
    this.blankCardI = -1;
    this.blankCardJ = -1;
    this.randomCount = 10;
    this.originCards = [];
  }

  start(): void{
    this.openDataDomObserver();
    //开启键盘监听
    this.addKeyBoardListener();
  }

  /**
   * 进入游戏后的监视
   *
   * callback函数为回调函数，
   */
  openDataDomObserver(): void {
    let that = this;
    let dom: HTMLElement = document.getElementById('data')!;
    let options = { attributes: true , characterData: true , childList: true , subtree: true };
    //<div id="data">{{ data }}</div>
    //当data的值改变，执行下面的回调函数
    //可以理解为游戏开始的回调函数
    function callback(mutationRecords: MutationRecord[]){
      if (mutationRecords[0].addedNodes.length !== 0) {
        console.log('进入游戏');
        
        //第一步：获取图片地址
        that.getImgUrl(mutationRecords[0]);
        //第二步：将图片组成dom元素
        that.initGameView();
        //第三步：将dom元素添加到Card类
        that.initCards();
        //第四步：打乱所有卡片
        that.randomAllCards();
        //第五步：设置一个空白卡片
        that.setRandomCardDonotVis();
        

        

        // that.printCards();

        // that.changeCard(that.cards[0][0] , that.cards[0][1]);


      } else {
        console.log('退出游戏');
        
        that.removeGameDom();
      }
    }
    let mutationObserver = new MutationObserver(callback);
    mutationObserver.observe(dom, options);
  }

  getImgUrl(mutationRecord: MutationRecord): void{
    this.imgUrl = mutationRecord.addedNodes[0].data as string;
  }

  //初始化card元素
  initCards(): void{
    let n = this.n;
    for (let i = 0 ; i < n ; i++) {
      let arr: Card[] = [];
      for (let j = 0 ; j < n ; j++) {
        let divName = `div${i}${j}`;
        let dom = document.getElementById(divName)!;
        let rect = dom.getBoundingClientRect();
        // console.log(rect)
        arr.push(new Card(dom));
      }
      this.cards.push(arr);
      this.originCards.push(arr);
    }
  }

  /**
   * 初始化游戏的界面，既将选择的图片分割成一块一块的
   */
  initGameView(): void{
    //生成m*n个div元素
     let m = this.n;
     let n = this.n;
     let frags = "<table id = 'fragTable' style='border: 5px'>";

    for(let i = 0; i < m; i++){
      frags += "<tr>";
      for(let j = 0; j < n; j++){
        frags += "<td><div id='div"+i+j+"'></div></td>";
      }
      frags += "</tr>";
    }
    frags += "</table>";

    document.getElementById("game_content")!.innerHTML = frags;

    this.addImage();
  }

  //为每个div添加背景图片
  addImage(): void{
    let m:number = this.n;
    let n:number = this.n;

    for(let i = 0; i < m; i++){
      for(let j = 0; j < n; j++){
        let curdiv=document.getElementById("div"+i+j)!;
        let wid = 650;
        let hgt = 500;
        curdiv.style.background=`url(${this.imgUrl}) no-repeat scroll`;
        curdiv.style.backgroundSize="650px 500px";
        curdiv.style.width=(wid/n)+"px";
        curdiv.style.height=(hgt/m)+"px";
        curdiv.style.backgroundPosition = this.getInverse(j*(wid/n))+
          "px"+' '+ this.getInverse(i*(hgt/m))+"px";
      }
    }
  }

  /**
   * 设置一个卡片为隐藏卡片
   */
  setRandomCardDonotVis(): void{
    let randomI = this.getRandomNum(0 , this.n - 1);
    let randomJ = this.getRandomNum(0 , this.n - 1);
    this.blankCardI = randomI;
    this.blankCardJ = randomJ;
    this.cards[randomI][randomJ].dom.style.display = 'none';
  }

  /**
   * 交换两个card
   * @param card1
   * @param card2
   * @private
   */
  changeCard(card1: Card, card2: Card) {
    let curCard: string = card1.dom.getAttribute("style")!;
    card1.dom.setAttribute("style" , card2.dom.getAttribute("style")!);
    card2.dom.setAttribute("style" , curCard);
  }

  /**
   * 添加键盘监听
   */
  addKeyBoardListener(): void{
    let that = this;
    document.onkeydown = function (event) {
      // console.log(event)
      that.keyboardOperation(event);
    }
  }

  /**
   * 键盘事件监听具体操作函数
   * @param e 
   */
  keyboardOperation(e: KeyboardEvent): void{
    console.log(`移动前:[${this.blankCardI},${this.blankCardJ}]`);
    
    if (e.key === 'ArrowUp') {  //上
      //1、如果当前空白卡片在最顶部，即blankI=0时，向上移动操作失败
      //2、如果当前空白卡片不在最顶部，则移动
      if (this.blankCardI !== 0) {
        //2.1、先移动两个卡片
        this.changeCard(this.cards[this.blankCardI][this.blankCardJ] , this.cards[this.blankCardI - 1][this.blankCardJ]);
        //2.2、再将空白卡片的坐标改变
        this.blankCardI--;
      }
    } else if (e.key === 'ArrowDown') { //下
      //1、如果当前卡片不在最底部，即blackI != n，即移动，反之不移动
      if (this.blankCardI !== this.n) {
        this.changeCard(this.cards[this.blankCardI][this.blankCardJ] , this.cards[this.blankCardI + 1][this.blankCardJ]);
        this.blankCardI++;
      }
    } else if (e.key === 'ArrowLeft') { //左
      //1、如果卡片不在最左边，即blankJ != 0,即移动，反之不移动
      if (this.blankCardJ !== 0) {
        this.changeCard(this.cards[this.blankCardI][this.blankCardJ] , this.cards[this.blankCardI][this.blankCardJ - 1]);
        this.blankCardJ--;
      }
    } else if (e.key === 'ArrowRight') {  //右
      //2、如果卡片不在最右边，即blankJ != n，即移动，反之不移动
      if (this.blankCardJ !== this.n) {
        this.changeCard(this.cards[this.blankCardI][this.blankCardJ] , this.cards[this.blankCardI][this.blankCardJ + 1]);
        this.blankCardJ++;
      }
    }

    console.log(`移动后:[${this.blankCardI},${this.blankCardJ}]`);
  }

  /**
   * 将所有的卡片随机排放
   */
  randomAllCards(): void{
    // let originArr: any[] = [];
    // let map = [];
    // //存入key
    // for (let i = 0 ; i < this.n * this.n ; i++) {
    //   originArr.push(i);
    // }
    // //设置对应的key-value
    // for (let i = 0 ; i < this.n; i++) {
    //   for (let j = 0 ; j < this.n ; j++) {
    //     map.push({
    //       i: i,
    //       j: j
    //     })
    //   }
    // }
    
    // console.log(map);
    
    for (let i = 0 ; i < this.randomCount ; i++) {
      let card1I = this.getRandomNum(0 , this.n);
      let card1J = this.getRandomNum(0 , this.n);
      let card2I = this.getRandomNum(0 , this.n);
      let card2J = this.getRandomNum(0 , this.n);
      console.log(`[${card1I},${card1J}]->[${card2I},${card2J}]`);
      
      this.changeCard(this.cards[card1I][card1J] , this.cards[card2I][card2J]);
    }
    
    
  }

  removeGameDom(): void{
    let gameDom = document.getElementById('fragTable')!;
    gameDom.remove();
  }



  //取相反数
  getInverse(num: number): number{
    return (0-num);
  }
  /**
   * 获取 a ~ b 的之间的值,[a,b]包含a和b \n
   * 例如 a=0,b=10    random(a,b) = 5
   * @param a
   * @param b
   * @private
   */
  getRandomNum(a: number, b: number): number{
    return Math.floor((Math.random()*b)+a);
  }

  printCards(): void{
    for (const i in this.cards) {
      for (const j in this.cards[i]) {

      }
    }
  }

}


new Game().start();
